#include <math.h>
#include <string>
#include <iostream>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::unique_ptr;

//纯虚函数作为接口存在，派生类实现这些纯虚函数即可完成功能的扩展
//
//当需求发生变化时，希望以最小的代价实现功能的扩展
class Figure
{
public:
    virtual string getName() const=0;
    virtual double getArea() const=0;
};


class Circle
: public Figure
{
public:
    Circle(double radius)
    : _radius(radius)
    {   cout << "Circle(double)" << endl;   }

    string getName() const override
    {   return string("circle");    }

    double getArea() const override
    {   return 3.14 * _radius * _radius;    }

private:
    double _radius;
};

class Rectangle
: public Figure
{
public:
    Rectangle(double length, double width)
    : _length(length)
    , _witdth(width)
    {   cout << "Rectangle(double,double)" << endl;}


    string getName() const override
    {   return string("rectangle");    }

    double getArea() const override
    {   return _length * _witdth;    }


private:
    double _length;
    double _witdth;
};

class Triangle
: public Figure
{
public:
    Triangle(double a, double b, double c)
    : _a(a), _b(b), _c(c)
    {   cout << "Triangle(double,double,double)" <<endl;}

    string getName() const override
    {   return string("triangle");    }

    double getArea() const override
    {   
        double p = (_a + _b + _c) / 2;
        return sqrt(p * (p - _a) * (p - _b) * (p - _c));    
    }

private:
    double _a, _b, _c;
};


//提取出了一个工厂的抽象类
//它生产的就是一种产品，但具体是什么产品，要交给其派生类来决定
class Factory
{
public:
    virtual Figure * create() = 0;
};

class CircleFactory
: public Factory
{
public:
    Figure * create()
    {
        //创建Circle时，半径的信息需要通过配置文件*.xml来获取
        //...load xml (预处理)
        Figure * fig = new Circle(10);
        return fig;
    }
};

class RectangleFactory
: public Factory
{
public:
    Figure * create()
    {
        //创建Rectangle时，半径的信息需要通过配置文件*.xml来获取
        //...load xml (预处理)
        Figure * fig = new Rectangle(10, 20);
        return fig;
    }
};

class TriangleFactory
: public Factory
{
public:
    Figure * create()
    {
        //创建Tirangle时，半径的信息需要通过配置文件*.xml来获取
        //...load xml (预处理)
        Figure * fig = new Triangle(3, 4, 5);
        return fig;
    }
};

class Test
{
public:
    Test(Factory * fact)
    : _fact(fact)
    {}

    void display()
    {
        cout << "Test::display()" << endl;
        //通过工厂来封装产品创建的过程
        Figure * fig = _fact->create();
        cout << fig->getName();
        cout << "的面积是:" << fig->getArea() << endl;
    }

private:
    Factory * _fact;
};

void test1()
{
    unique_ptr<Factory> pCircleFactory(new CircleFactory);
    Test test(pCircleFactory.get());
    test.display();
}

void display(Figure & fig)
{
    cout << fig.getName();
    cout << "的面积是:" << fig.getArea() << endl;
}


int test0()
{
    //当对象的创建不再是很简单的情况下，而是比较复杂的情况下，
    //那就可以使用工厂模式(工厂方法)
    //优势：满足单一职责原则和开闭原则
    unique_ptr<Factory> pCircleFactory(new CircleFactory); 
    unique_ptr<Figure> pCircle(pCircleFactory->create());

    unique_ptr<Factory> pRectangFactory(new RectangleFactory);
    unique_ptr<Figure> pRectangle(pRectangFactory->create());

    unique_ptr<Factory> pTriangleFactory(new TriangleFactory);
    unique_ptr<Figure> pTriangle(pTriangleFactory->create());

    display(*pCircle);
    display(*pRectangle);
    display(*pTriangle);

    return 0;
}

int main()
{
    test1();
    return 0;
}

